module qtrt

import ffi
import os

pub fn setAllInheritCallback(cbobj voidptr, name string, f voidptr) {
    inherit_add(cbobj, name, f)
}

pub fn unsetAllInheritCallback(cbobj voidptr, name string) {
}

fn setAllInheritCallback2c(name string, fnptr voidptr) {
	// symname := fmt.Sprintf("set_callback%s", name)
	// InvokeQtFunc6(symname, FFI_TYPE_VOID, fnptr)
    symname := "set_callback${name}"
    ccfn := sym_cfunc6(0, symname)
    assert(ccfn != voidptr(0))

    mut atypes := []int{}
    atypes << ffi.TYPE_POINTER
    mut avalues := []voidptr{}
    avalues << &fnptr
    rv := ffi.call3(ccfn, atypes, avalues)
    // println("rv=${rv}")
}

fn init_callack_inherit() {
	dbgval := os.getenv("QTGO_DEBUG_INHERIT_CALL")
    if dbgval.to_lower() == "true" || dbgval == "1" {
        mut rtv := rtg
        rtv.debugIneritCall = true
    }

    setAllInheritCallback2c("AllInherits", callback_all_inherit)
}
pub fn setDebugAllInheritsFilterFunc(f fn(name string) bool) {
    mut rtv := rtg
    rtv.debugAllInheritsFilterFunc = f
}

// protected inherit method callback function type
type TProtCbfn0 = fn()
type TProtCbfn1 = fn(voidptr)
type TProtCbfn2 = fn(voidptr, voidptr)
type TProtCbfn3 = fn(voidptr, voidptr, voidptr)

// TODO support non pointer type px
// 在C绑定中的projected继承代理方法直接调用
// //export callbackAllInherits
fn callback_all_inherit(cbobj voidptr, iname byteptr, handled &int, argc int, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9 u64) u64 {
    vname := tos_clone(iname)

    logmsg := @FN+" hehehe $cbobj $vname argc=$argc"
    // defer {logmsg.free()}
    println(logmsg)

    // TODO need to know parameter type
    cbfn := inherit_get(cbobj, vname)
    if cbfn != voidptr(0) {
        println("iname $vname, $cbfn, argc=$argc")
        mut atypes := []int{}
        mut avalues :=[]voidptr{}
        match argc {
            0 {
                fnptr := TProtCbfn0(cbfn)
                fnptr()
            }
            1 {
                fnptr := TProtCbfn1(cbfn)
                fnptr(voidptr(p0))
            }
            2 {
                fnptr := TProtCbfn2(cbfn)
                fnptr(voidptr(p0),voidptr(p1))
            }
            3 {
                fnptr := TProtCbfn3(cbfn)
                fnptr(voidptr(p0),voidptr(p1),voidptr(p2))
            }
            else {}
        }
        // not need ffi call, until know parameter type
        /*
        if argc > 0 {
            atypes << ffi.TYPE_POINTER
            avalues << voidptr(&p0)
        }
        if argc > 1 {
            atypes << ffi.TYPE_POINTER
            avalues << voidptr(&p1)
        }
        if argc > 2 {
            atypes << ffi.TYPE_POINTER
            avalues << voidptr(&p2)
        }
        ffi.call3(cbfn, atypes, avalues)
        */
    }

    return 0
}

/////////
struct InheritHandler {
    pub mut:
    items map[string]map[string]voidptr
}

struct InheritName {
    pub mut:
    items map[string]voidptr
}

fn newInheritHandler() &InheritHandler {
    this := &InheritHandler{}
    return this
}

fn newNullInheritHandler() &InheritHandler {
    return voidptr(0)
}

pub fn inherit_add(obj voidptr, fname string, cbfn voidptr) {
    mut rtv := rtg
    mut inh := rtg.inh

    objstr := "${obj}"
    if objstr in inh.items {
        if fname in inh.items[objstr] {
            rtv.l.warn("already exist $objstr $fname")
        }else{
            inh.items[objstr][fname] = cbfn
        }
    }else{
        mut m1 := map[string]voidptr{}
        m1[fname] = cbfn
        rtv.inh.items[objstr] = m1
    }
    maplen := inh.items.len
    maplen2 := rtg.inh.items.len
    maplen3 := rtg.inh.items[objstr].len
    maplen4 := rtv.inh.items[objstr].len
    println("inherit_add $objstr, $fname, $cbfn, $maplen, $maplen2, $maplen3, $maplen4")
}

pub fn inherit_del(obj voidptr, fname string) {

}

pub fn inherit_get(obj voidptr, fname string) voidptr {
    rtv := rtg
    inh := rtg.inh

    objstr := "${obj}"
    if objstr in inh.items {
        if fname in inh.items[objstr] {
            return inh.items[objstr][fname]
        }
    }
    return voidptr(0)
}
